package com.demo.crm.security.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.MediaType;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;

/**
 * @author tanshuai
 */
@Slf4j
public class ExceptionFilter extends GenericFilterBean {

    private static MediaTypeRequestMatcher jsonMediaTypeRequestMatcher = new MediaTypeRequestMatcher(new HeaderContentNegotiationStrategy(), MediaType.APPLICATION_JSON);
    private String failureUrl;
    private static RedirectStrategy redirectStrategy;

    @Override
    protected void initFilterBean() throws ServletException {
        jsonMediaTypeRequestMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
    }

    public void setFailureUrl(String failureUrl) {
        this.failureUrl = failureUrl;
    }

    public void setRedirectStrategy(RedirectStrategy defaultRedirectStrategy) {
        redirectStrategy = defaultRedirectStrategy;
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } catch (Exception e) {
            log.error("", e);

            Throwable rootCause = ExceptionUtils.getRootCause(e);
            String exceptionMsg = (rootCause == null ? e.getMessage() : rootCause.getMessage());
            handleFailure(exceptionMsg, failureUrl, servletRequest, servletResponse);
        }
    }

    public static void handleFailure(Object exceptionMsg, String redirectUrl, ServletRequest servletRequest, ServletResponse servletResponse) {
        log.error("异常：{}", exceptionMsg);

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.reset();
        try {
            if (jsonMediaTypeRequestMatcher.matches(request)) {
                response.setStatus(500);
                PrintWriter writer = response.getWriter();
                writer.write(String.valueOf(exceptionMsg));
                writer.close();
            } else {
                request.getSession().setAttribute("errorMsg", exceptionMsg);
                redirectStrategy.sendRedirect(request, response, redirectUrl);
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }
}
